package com.eoi.docs.util;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.json.JsonParserFactory;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * Created by tao.zeng on 2023/4/6.
 */
@Slf4j
public class JsonParse {

    /**
     * The constant EMPTY_OBJECT.
     */
    private final static String EMPTY_OBJECT = "{}";
    /**
     * The constant EMPTY_LIST.
     */
    private final static String EMPTY_LIST = "[]";

    /**
     * The constant OBJECT_MAPPER.
     */
    private final static ObjectMapper OBJECT_MAPPER = buildObjectMapper();

    /**
     * Build object mapper object mapper.
     *
     * @return the object mapper
     */
    static ObjectMapper buildObjectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        // Java8 日期序列化反序列化处理
        objectMapper.registerModule(new JavaTimeModule());
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                .configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true)
                .configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true)
                .configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true)
                // .configure(com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT, true)
                .configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, false);

        SimpleModule simpleModule = new SimpleModule();

        /*
         *  将Long,BigInteger,BigDecimal序列化的时候,转化为String
         */
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance);
        simpleModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);

        objectMapper.registerModule(simpleModule);
        return objectMapper;
    }

    /**
     * To json string.
     *
     * @param bean the bean
     * @return the string
     * @throws JsonProcessingException the json processing exception
     */
    public static String toJson(Object bean) throws JsonProcessingException {
        return OBJECT_MAPPER.writeValueAsString(bean);
    }

    /**
     * Try to json string.
     *
     * @param bean the bean
     * @return the string
     */
    public static String tryToJson(Object bean) {
        try {
            return OBJECT_MAPPER.writeValueAsString(bean);
        } catch (JsonProcessingException e) {
            log.warn("JsonProcessingException,", e);
        }
        return bean instanceof Collection ? EMPTY_LIST : EMPTY_OBJECT;
    }

    /**
     * To json pretty printer string.
     *
     * @param bean the bean
     * @return the string
     */
    public static String toJsonPrettyPrinter(Object bean) {
        try {
            return OBJECT_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(bean);
        } catch (JsonProcessingException e) {
            log.warn("JsonProcessingException,", e);
        }
        return bean instanceof Collection ? EMPTY_LIST : EMPTY_OBJECT;
    }

    /**
     * Parse t.
     *
     * @param <T>  the type parameter
     * @param json the json
     * @param clz  the clz
     * @return the t
     * @throws IOException the io exception
     */
    public static <T> T parse(String json, Class<T> clz) throws IOException {
        if (StringUtils.isEmpty(json)) return null;
        return OBJECT_MAPPER.readValue(json, clz);
    }

    /**
     * Parse t.
     *
     * @param <T>  the type parameter
     * @param json the json
     * @param type the type
     * @return the t
     * @throws IOException the io exception
     */
    public static <T> T parse(String json, TypeReference<T> type) throws IOException {
        if (StringUtils.isEmpty(json)) return null;
        return OBJECT_MAPPER.readValue(json, type);
    }

    /**
     * Try parse t.
     *
     * @param <T>  the type parameter
     * @param json the json
     * @param clz  the clz
     * @return the t
     */
    public static <T> T tryParse(String json, Class<T> clz) {
        if (StringUtils.isEmpty(json)) return null;
        try {
            return OBJECT_MAPPER.readValue(json, clz);
        } catch (IOException e) {
            log.warn("IOException,", e);
        }
        return null;
    }

    /**
     * Try parse t.
     *
     * @param <T>  the type parameter
     * @param json the json
     * @param type the type example: new TypeReference<Map<String, Object>>() { }
     * @return the t
     */
    public static <T> T tryParse(String json, TypeReference<T> type) {
        if (StringUtils.isEmpty(json)) return null;
        try {
            return OBJECT_MAPPER.readValue(json, type);
        } catch (IOException e) {
            log.warn("IOException,", e);
        }
        return null;
    }

    /**
     * Parse map map.
     *
     * @param json the json
     * @return the map
     */
    public static Map<String, Object> parseMap(String json) {
        return JsonParserFactory.getJsonParser().parseMap(json);
    }

    /**
     * Parse list list.
     *
     * @param json the json
     * @return the list
     */
    public static List<Object> parseList(String json) {
        return JsonParserFactory.getJsonParser().parseList(json);
    }
}
